package main

import (
	"fmt"
	"os"
	"time"
)

// ==========================================
// 自定义错误类型
// ==========================================

// 定义自定义错误类型
type ValidationError struct {
	Field string
	Issue string
}

// 实现error接口
func (e *ValidationError) Error() string {
	return fmt.Sprintf("验证错误: %s %s", e.Field, e.Issue)
}

// 定义包装错误类型
type QueryError struct {
	Query string
	Err   error // 包装底层错误
}

func (e *QueryError) Error() string {
	return fmt.Sprintf("查询错误 [%s]: %v", e.Query, e.Err)
}

// 实现Unwrap方法以支持错误链
func (e *QueryError) Unwrap() error {
	return e.Err
}

func main() {
	// ==========================================
	// 基本错误处理
	// ==========================================

	// 1. 基本错误检查
	result, err := divide(10, 2)
	if err != nil {
		fmt.Println("错误:", err)
	} else {
		fmt.Printf("10 / 2 = %.2f\n", result)
	}

	result, err = divide(10, 0)
	if err != nil {
		fmt.Println("错误:", err)
	} else {
		fmt.Printf("10 / 0 = %.2f\n", result)
	}

	// 2. 使用errors.New创建错误
	err = validateAge(-5)
	if err != nil {
		fmt.Println("验证错误:", err)
	}

	// 3. 使用fmt.Errorf创建带格式的错误
	name := ""
	err = validateName(name)
	if err != nil {
		fmt.Println("验证错误:", err)
	}

	// ==========================================
	// 自定义错误类型的使用
	// ==========================================

	// 使用自定义ValidationError
	err = validateUser("", 0)
	if err != nil {
		// 类型断言判断具体错误类型
		if validErr, ok := err.(*ValidationError); ok {
			fmt.Printf("发生验证错误 - 字段: %s, 问题: %s\n", validErr.Field, validErr.Issue)
		} else {
			fmt.Println("发生其他错误:", err)
		}
	}

	// ==========================================
	// 错误包装和解包
	// ==========================================

	// 1. 错误包装
	err = executeQuery("SELECT * FROM users")
	if err != nil {
		fmt.Println("查询执行错误:", err)

		// 2. 错误解包
		if queryErr := new(QueryError); errors.As(err, &queryErr) {
			fmt.Printf("原始查询: %s\n", queryErr.Query)
		}

		// 3. 检查特定错误
		if errors.Is(err, io.EOF) {
			fmt.Println("遇到EOF错误")
		}
	}

	// ==========================================
	// panic和recover
	// ==========================================

	fmt.Println("\n=== panic和recover示例 ===")

	// 使用defer和recover捕获panic
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("已恢复的panic: %v\n", r)
		}
	}()

	// 调用可能会panic的函数
	processSomething()

	// 这行不会执行，因为上面的函数会panic
	fmt.Println("这行不会执行")

	// ==========================================
	// defer的使用
	// ==========================================

	fmt.Println("\n=== defer示例 ===")

	// 1. 基本defer用法
	deferExample()

	// 2. defer和命名返回值
	result = deferWithNamedReturn()
	fmt.Printf("命名返回值结果: %.2f\n", result)

	// 3. defer的执行顺序
	deferOrder()

	// ==========================================
	// 使用context进行超时和取消
	// ==========================================

	fmt.Println("\n=== context示例 ===")

	// 创建一个带取消的context
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // 确保所有路径都会调用cancel

	// 启动一个长时间运行的操作
	go func() {
		err := longRunningOperation(ctx)
		if err != nil {
			fmt.Println("操作错误:", err)
		}
	}()

	// 等待一段时间看结果
	time.Sleep(3 * time.Second)

	// ==========================================
	// 文件操作中的错误处理
	// ==========================================

	fmt.Println("\n=== 文件操作错误处理示例 ===")

	// 写入文件
	err = writeToFile("test.txt", "Hello, Go!")
	if err != nil {
		fmt.Println("写入文件错误:", err)
	}

	// 读取文件
	content, err := readFromFile("test.txt")
	if err != nil {
		fmt.Println("读取文件错误:", err)
	} else {
		fmt.Println("文件内容:", content)
	}

	// 清理：删除测试文件
	os.Remove("test.txt")

	// ==========================================
	// 练习
	// ==========================================

	// 1. 创建一个函数，验证用户输入，返回自定义错误

	// 2. 实现一个函数，模拟数据库操作，使用错误包装

	// 3. 编写一个使用panic/recover的示例

	// 4. 创建一个带有超时的context示例

	// 5. 实现一个资源清理的defer示例
}

// ==========================================
// 辅助函数
// ==========================================

// 基本的除法函数
func divide(a, b float64) (float64, error) {
	if b == 0 {
		return 0, errors.New("除数不能为零")
	}
	return a / b, nil
}

// 年龄验证函数
func validateAge(age int) error {
	if age < 0 {
		return errors.New("年龄不能为负数")
	}
	if age > 150 {
		return errors.New("年龄不能超过150岁")
	}
	return nil
}

// 名字验证函数
func validateName(name string) error {
	if name == "" {
		return fmt.Errorf("名字不能为空")
	}
	if len(name) < 2 {
		return fmt.Errorf("名字长度必须大于2个字符（当前长度：%d）", len(name))
	}
	return nil
}

// 用户验证函数
func validateUser(name string, age int) error {
	if name == "" {
		return &ValidationError{Field: "name", Issue: "不能为空"}
	}
	if age <= 0 {
		return &ValidationError{Field: "age", Issue: "必须大于0"}
	}
	return nil
}

// 模拟数据库查询
func executeQuery(query string) error {
	// 模拟数据库错误
	err := fmt.Errorf("数据库连接失败")
	return &QueryError{
		Query: query,
		Err:   err,
	}
}

// 可能会panic的函数
func processSomething() {
	numbers := []int{1, 2, 3}
	// 故意访问超出切片范围的索引
	fmt.Println(numbers[10])
}

// defer示例函数
func deferExample() {
	fmt.Println("开始执行函数")
	defer fmt.Println("第一个defer")
	defer fmt.Println("第二个defer")
	fmt.Println("函数执行结束")
}

// 带命名返回值的defer函数
func deferWithNamedReturn() (result float64) {
	result = 1.0
	defer func() {
		result *= 2 // 修改命名返回值
	}()
	return 5.0
}

// defer执行顺序示例
func deferOrder() {
	for i := 0; i < 3; i++ {
		defer fmt.Printf("defer %d\n", i)
	}
}

// 长时间运行的操作
func longRunningOperation(ctx context.Context) error {
	// 创建一个通道用于发送结果
	done := make(chan error, 1)

	go func() {
		// 模拟耗时操作
		time.Sleep(3 * time.Second)
		done <- nil
	}()

	// 等待操作完成或context取消
	select {
	case err := <-done:
		return err
	case <-ctx.Done():
		return ctx.Err()
	}
}

// 写入文件
func writeToFile(filename string, content string) error {
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("创建文件错误: %w", err)
	}
	defer file.Close()

	_, err = file.WriteString(content)
	if err != nil {
		return fmt.Errorf("写入文件错误: %w", err)
	}

	return nil
}

// 读取文件
func readFromFile(filename string) (string, error) {
	content, err := os.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("读取文件错误: %w", err)
	}

	return string(content), nil
}

// ==========================================
// 练习参考实现
// ==========================================

// 1. 用户输入验证
type UserInputError struct {
	Input string
	Issue string
}

func (e *UserInputError) Error() string {
	return fmt.Sprintf("无效的输入 '%s': %s", e.Input, e.Issue)
}

func validateInput(input string) error {
	if len(input) == 0 {
		return &UserInputError{Input: input, Issue: "输入不能为空"}
	}
	if len(input) < 3 {
		return &UserInputError{Input: input, Issue: "输入长度必须大于3个字符"}
	}
	return nil
}

// 2. 模拟数据库操作
type DBError struct {
	Operation string
	Err       error
}

func (e *DBError) Error() string {
	return fmt.Sprintf("数据库操作 '%s' 失败: %v", e.Operation, e.Err)
}

func (e *DBError) Unwrap() error {
	return e.Err
}

func simulateDBOperation() error {
	// 模拟数据库错误
	err := errors.New("连接超时")
	return &DBError{
		Operation: "查询用户",
		Err:       err,
	}
}

// 3. panic/recover示例
func dangerousOperation() (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("操作恢复自panic: %v", r)
		}
	}()

	// 模拟一些可能导致panic的操作
	panic("发生了一些非常糟糕的事情")
}

// 4. 带超时的操作
func operationWithTimeout(timeout time.Duration) error {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	done := make(chan bool)
	go func() {
		// 模拟耗时操作
		time.Sleep(2 * time.Second)
		done <- true
	}()

	select {
	case <-done:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

// 5. 资源清理示例
type Resource struct {
	name string
}

func (r *Resource) Close() error {
	fmt.Printf("清理资源: %s\n", r.name)
	return nil
}

func useResource() error {
	r := &Resource{name: "数据库连接"}
	defer r.Close()

	// 使用资源
	fmt.Printf("使用资源: %s\n", r.name)
	return nil
}
